/*
 *
 *    Copyright (c) 2021 Project CHIP Authors
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

// THIS FILE IS GENERATED BY ZAP

#include <cinttypes>
#include <cstdint>

#include "af-structs.h"
#include "app/util/util.h"
#include "call-command-handler.h"
#include "callback.h"
#include "cluster-id.h"
#include "command-id.h"

#include <app/InteractionModelEngine.h>

// Currently we need some work to keep compatible with ember lib.
#include <app/util/ember-compatibility-functions.h>

namespace chip {
namespace app {

// Cluster specific command parsing

namespace clusters {

namespace GeneralCommissioning {

void DispatchServerCommand(app::Command * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv)
{
    {
        switch (aCommandId)
        {
        case ZCL_ARM_FAIL_SAFE_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            uint16_t expiryLengthSeconds;
            bool expiryLengthSecondsExists = false;
            uint64_t breadcrumb;
            bool breadcrumbExists = false;
            uint32_t timeoutMs;
            bool timeoutMsExists        = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (expiryLengthSecondsExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(expiryLengthSeconds);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        expiryLengthSecondsExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (breadcrumbExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(breadcrumb);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        breadcrumbExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 2:
                    if (timeoutMsExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(timeoutMs);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        timeoutMsExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfGeneralCommissioningClusterArmFailSafeCallback(apCommandObj, expiryLengthSeconds, breadcrumb, timeoutMs);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    3, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_COMMISSIONING_COMPLETE_COMMAND_ID: {

            // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
            emberAfGeneralCommissioningClusterCommissioningCompleteCallback(apCommandObj);
            break;
        }
        case ZCL_SET_REGULATORY_CONFIG_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            uint8_t location;
            bool locationExists = false;
            const uint8_t * countryCode;
            bool countryCodeExists = false;
            uint64_t breadcrumb;
            bool breadcrumbExists = false;
            uint32_t timeoutMs;
            bool timeoutMsExists        = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (locationExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(location);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        locationExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (countryCodeExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    // TODO(#5542): The cluster handlers should accept a ByteSpan for all string types.
                    TLVUnpackError = aDataTlv.GetDataPtr(countryCode);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        countryCodeExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 2:
                    if (breadcrumbExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(breadcrumb);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        breadcrumbExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 3:
                    if (timeoutMsExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(timeoutMs);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        timeoutMsExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfGeneralCommissioningClusterSetRegulatoryConfigCallback(
                    apCommandObj, location, const_cast<uint8_t *>(countryCode), breadcrumb, timeoutMs);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    4, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        default: {
            // Unrecognized command ID, error status will apply.
            apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kNotFound,
                                        Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
            ChipLogError(Zcl, "Unknown command %" PRIx16 " for cluster %" PRIx16, aCommandId, ZCL_GENERAL_COMMISSIONING_CLUSTER_ID);
            break;
        }
        }
    }
}

} // namespace GeneralCommissioning

namespace LevelControl {

void DispatchServerCommand(app::Command * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv)
{
    {
        switch (aCommandId)
        {
        case ZCL_MOVE_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            uint8_t moveMode;
            bool moveModeExists = false;
            uint8_t rate;
            bool rateExists = false;
            uint8_t optionMask;
            bool optionMaskExists = false;
            uint8_t optionOverride;
            bool optionOverrideExists   = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (moveModeExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(moveMode);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        moveModeExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (rateExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(rate);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        rateExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 2:
                    if (optionMaskExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(optionMask);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        optionMaskExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 3:
                    if (optionOverrideExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(optionOverride);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        optionOverrideExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfLevelControlClusterMoveCallback(apCommandObj, moveMode, rate, optionMask, optionOverride);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    4, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_MOVE_TO_LEVEL_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            uint8_t level;
            bool levelExists = false;
            uint16_t transitionTime;
            bool transitionTimeExists = false;
            uint8_t optionMask;
            bool optionMaskExists = false;
            uint8_t optionOverride;
            bool optionOverrideExists   = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (levelExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(level);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        levelExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (transitionTimeExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(transitionTime);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        transitionTimeExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 2:
                    if (optionMaskExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(optionMask);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        optionMaskExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 3:
                    if (optionOverrideExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(optionOverride);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        optionOverrideExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfLevelControlClusterMoveToLevelCallback(apCommandObj, level, transitionTime, optionMask, optionOverride);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    4, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_MOVE_TO_LEVEL_WITH_ON_OFF_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            uint8_t level;
            bool levelExists = false;
            uint16_t transitionTime;
            bool transitionTimeExists   = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (levelExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(level);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        levelExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (transitionTimeExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(transitionTime);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        transitionTimeExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 2 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfLevelControlClusterMoveToLevelWithOnOffCallback(apCommandObj, level, transitionTime);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    2, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_MOVE_WITH_ON_OFF_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            uint8_t moveMode;
            bool moveModeExists = false;
            uint8_t rate;
            bool rateExists             = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (moveModeExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(moveMode);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        moveModeExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (rateExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(rate);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        rateExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 2 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfLevelControlClusterMoveWithOnOffCallback(apCommandObj, moveMode, rate);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    2, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_STEP_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            uint8_t stepMode;
            bool stepModeExists = false;
            uint8_t stepSize;
            bool stepSizeExists = false;
            uint16_t transitionTime;
            bool transitionTimeExists = false;
            uint8_t optionMask;
            bool optionMaskExists = false;
            uint8_t optionOverride;
            bool optionOverrideExists   = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (stepModeExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(stepMode);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        stepModeExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (stepSizeExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(stepSize);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        stepSizeExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 2:
                    if (transitionTimeExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(transitionTime);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        transitionTimeExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 3:
                    if (optionMaskExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(optionMask);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        optionMaskExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 4:
                    if (optionOverrideExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(optionOverride);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        optionOverrideExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfLevelControlClusterStepCallback(apCommandObj, stepMode, stepSize, transitionTime, optionMask,
                                                       optionOverride);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    5, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_STEP_WITH_ON_OFF_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            uint8_t stepMode;
            bool stepModeExists = false;
            uint8_t stepSize;
            bool stepSizeExists = false;
            uint16_t transitionTime;
            bool transitionTimeExists   = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (stepModeExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(stepMode);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        stepModeExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (stepSizeExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(stepSize);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        stepSizeExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 2:
                    if (transitionTimeExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(transitionTime);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        transitionTimeExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfLevelControlClusterStepWithOnOffCallback(apCommandObj, stepMode, stepSize, transitionTime);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    3, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_STOP_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            uint8_t optionMask;
            bool optionMaskExists = false;
            uint8_t optionOverride;
            bool optionOverrideExists   = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (optionMaskExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(optionMask);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        optionMaskExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (optionOverrideExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(optionOverride);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        optionOverrideExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 2 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfLevelControlClusterStopCallback(apCommandObj, optionMask, optionOverride);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    2, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_STOP_WITH_ON_OFF_COMMAND_ID: {

            // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
            emberAfLevelControlClusterStopWithOnOffCallback(apCommandObj);
            break;
        }
        default: {
            // Unrecognized command ID, error status will apply.
            apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kNotFound,
                                        Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
            ChipLogError(Zcl, "Unknown command %" PRIx16 " for cluster %" PRIx16, aCommandId, ZCL_LEVEL_CONTROL_CLUSTER_ID);
            break;
        }
        }
    }
}

} // namespace LevelControl

namespace NetworkCommissioning {

void DispatchServerCommand(app::Command * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv)
{
    {
        switch (aCommandId)
        {
        case ZCL_ADD_THREAD_NETWORK_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            chip::ByteSpan operationalDataset;
            bool operationalDatasetExists = false;
            uint64_t breadcrumb;
            bool breadcrumbExists = false;
            uint32_t timeoutMs;
            bool timeoutMsExists        = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (operationalDatasetExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    {
                        const uint8_t * data = nullptr;
                        TLVUnpackError       = aDataTlv.GetDataPtr(data);
                        operationalDataset   = chip::ByteSpan(data, aDataTlv.GetLength());
                    }
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        operationalDatasetExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (breadcrumbExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(breadcrumb);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        breadcrumbExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 2:
                    if (timeoutMsExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(timeoutMs);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        timeoutMsExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfNetworkCommissioningClusterAddThreadNetworkCallback(apCommandObj, operationalDataset, breadcrumb, timeoutMs);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    3, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_ADD_WI_FI_NETWORK_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            chip::ByteSpan ssid;
            bool ssidExists = false;
            chip::ByteSpan credentials;
            bool credentialsExists = false;
            uint64_t breadcrumb;
            bool breadcrumbExists = false;
            uint32_t timeoutMs;
            bool timeoutMsExists        = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (ssidExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    {
                        const uint8_t * data = nullptr;
                        TLVUnpackError       = aDataTlv.GetDataPtr(data);
                        ssid                 = chip::ByteSpan(data, aDataTlv.GetLength());
                    }
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        ssidExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (credentialsExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    {
                        const uint8_t * data = nullptr;
                        TLVUnpackError       = aDataTlv.GetDataPtr(data);
                        credentials          = chip::ByteSpan(data, aDataTlv.GetLength());
                    }
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        credentialsExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 2:
                    if (breadcrumbExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(breadcrumb);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        breadcrumbExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 3:
                    if (timeoutMsExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(timeoutMs);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        timeoutMsExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfNetworkCommissioningClusterAddWiFiNetworkCallback(apCommandObj, ssid, credentials, breadcrumb, timeoutMs);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    4, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_DISABLE_NETWORK_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            chip::ByteSpan networkID;
            bool networkIDExists = false;
            uint64_t breadcrumb;
            bool breadcrumbExists = false;
            uint32_t timeoutMs;
            bool timeoutMsExists        = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (networkIDExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    {
                        const uint8_t * data = nullptr;
                        TLVUnpackError       = aDataTlv.GetDataPtr(data);
                        networkID            = chip::ByteSpan(data, aDataTlv.GetLength());
                    }
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        networkIDExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (breadcrumbExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(breadcrumb);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        breadcrumbExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 2:
                    if (timeoutMsExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(timeoutMs);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        timeoutMsExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfNetworkCommissioningClusterDisableNetworkCallback(apCommandObj, networkID, breadcrumb, timeoutMs);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    3, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_ENABLE_NETWORK_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            chip::ByteSpan networkID;
            bool networkIDExists = false;
            uint64_t breadcrumb;
            bool breadcrumbExists = false;
            uint32_t timeoutMs;
            bool timeoutMsExists        = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (networkIDExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    {
                        const uint8_t * data = nullptr;
                        TLVUnpackError       = aDataTlv.GetDataPtr(data);
                        networkID            = chip::ByteSpan(data, aDataTlv.GetLength());
                    }
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        networkIDExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (breadcrumbExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(breadcrumb);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        breadcrumbExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 2:
                    if (timeoutMsExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(timeoutMs);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        timeoutMsExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfNetworkCommissioningClusterEnableNetworkCallback(apCommandObj, networkID, breadcrumb, timeoutMs);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    3, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_GET_LAST_NETWORK_COMMISSIONING_RESULT_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            uint32_t timeoutMs;
            bool timeoutMsExists        = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (timeoutMsExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(timeoutMs);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        timeoutMsExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 1 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfNetworkCommissioningClusterGetLastNetworkCommissioningResultCallback(apCommandObj, timeoutMs);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    1, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_REMOVE_NETWORK_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            chip::ByteSpan NetworkID;
            bool NetworkIDExists = false;
            uint64_t Breadcrumb;
            bool BreadcrumbExists = false;
            uint32_t TimeoutMs;
            bool TimeoutMsExists        = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (NetworkIDExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    {
                        const uint8_t * data = nullptr;
                        TLVUnpackError       = aDataTlv.GetDataPtr(data);
                        NetworkID            = chip::ByteSpan(data, aDataTlv.GetLength());
                    }
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        NetworkIDExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (BreadcrumbExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(Breadcrumb);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        BreadcrumbExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 2:
                    if (TimeoutMsExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(TimeoutMs);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        TimeoutMsExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfNetworkCommissioningClusterRemoveNetworkCallback(apCommandObj, NetworkID, Breadcrumb, TimeoutMs);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    3, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_SCAN_NETWORKS_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            chip::ByteSpan ssid;
            bool ssidExists = false;
            uint64_t breadcrumb;
            bool breadcrumbExists = false;
            uint32_t timeoutMs;
            bool timeoutMsExists        = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (ssidExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    {
                        const uint8_t * data = nullptr;
                        TLVUnpackError       = aDataTlv.GetDataPtr(data);
                        ssid                 = chip::ByteSpan(data, aDataTlv.GetLength());
                    }
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        ssidExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (breadcrumbExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(breadcrumb);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        breadcrumbExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 2:
                    if (timeoutMsExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(timeoutMs);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        timeoutMsExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfNetworkCommissioningClusterScanNetworksCallback(apCommandObj, ssid, breadcrumb, timeoutMs);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    3, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_UPDATE_THREAD_NETWORK_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            chip::ByteSpan operationalDataset;
            bool operationalDatasetExists = false;
            uint64_t breadcrumb;
            bool breadcrumbExists = false;
            uint32_t timeoutMs;
            bool timeoutMsExists        = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (operationalDatasetExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    {
                        const uint8_t * data = nullptr;
                        TLVUnpackError       = aDataTlv.GetDataPtr(data);
                        operationalDataset   = chip::ByteSpan(data, aDataTlv.GetLength());
                    }
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        operationalDatasetExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (breadcrumbExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(breadcrumb);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        breadcrumbExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 2:
                    if (timeoutMsExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(timeoutMs);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        timeoutMsExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfNetworkCommissioningClusterUpdateThreadNetworkCallback(apCommandObj, operationalDataset, breadcrumb,
                                                                              timeoutMs);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    3, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        case ZCL_UPDATE_WI_FI_NETWORK_COMMAND_ID: {
            // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
            // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
            // Any error value TLVUnpackError means we have received an illegal value.
            CHIP_ERROR TLVError       = CHIP_NO_ERROR;
            CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
            chip::ByteSpan ssid;
            bool ssidExists = false;
            chip::ByteSpan credentials;
            bool credentialsExists = false;
            uint64_t breadcrumb;
            bool breadcrumbExists = false;
            uint32_t timeoutMs;
            bool timeoutMsExists        = false;
            uint32_t validArgumentCount = 0;

            while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
            {
                switch (TLV::TagNumFromTag(aDataTlv.GetTag()))
                {
                case 0:
                    if (ssidExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    {
                        const uint8_t * data = nullptr;
                        TLVUnpackError       = aDataTlv.GetDataPtr(data);
                        ssid                 = chip::ByteSpan(data, aDataTlv.GetLength());
                    }
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        ssidExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 1:
                    if (credentialsExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    {
                        const uint8_t * data = nullptr;
                        TLVUnpackError       = aDataTlv.GetDataPtr(data);
                        credentials          = chip::ByteSpan(data, aDataTlv.GetLength());
                    }
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        credentialsExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 2:
                    if (breadcrumbExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(breadcrumb);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        breadcrumbExists = true;
                        validArgumentCount++;
                    }
                    break;
                case 3:
                    if (timeoutMsExists)
                    {
                        ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
                        TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
                        break;
                    }
                    TLVUnpackError = aDataTlv.Get(timeoutMs);
                    if (CHIP_NO_ERROR == TLVUnpackError)
                    {
                        timeoutMsExists = true;
                        validArgumentCount++;
                    }
                    break;
                default:
                    // Unsupported tag, ignore it.
                    ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
                    break;
                }
                if (TLVUnpackError != CHIP_NO_ERROR)
                {
                    ChipLogProgress(Zcl, "Failed to decode TLV data with tag %" PRIx32 ": %" PRId32,
                                    TLV::TagNumFromTag(aDataTlv.GetTag()), TLVUnpackError);
                    break;
                }
            }

            if (CHIP_END_OF_TLV == TLVError)
            {
                // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
                TLVError = CHIP_NO_ERROR;
            }
            else
            {
                ChipLogProgress(Zcl, "Failed to decode TLV data: %" PRId32, TLVError);
            }

            // TODO(#5590) We should encode a response of status code for invalid TLV.
            if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
            {
                // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
                emberAfNetworkCommissioningClusterUpdateWiFiNetworkCallback(apCommandObj, ssid, credentials, breadcrumb, timeoutMs);
            }
            else
            {
                apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
                                            Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
                ChipLogProgress(
                    Zcl, "Failed to dispatch command, %d/%" PRIu32 " arguments parsed, TLVError=%" PRIu32 ", UnpackError=%" PRIu32,
                    4, validArgumentCount, TLVError, TLVUnpackError);
            }
            break;
        }
        default: {
            // Unrecognized command ID, error status will apply.
            apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kNotFound,
                                        Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
            ChipLogError(Zcl, "Unknown command %" PRIx16 " for cluster %" PRIx16, aCommandId, ZCL_NETWORK_COMMISSIONING_CLUSTER_ID);
            break;
        }
        }
    }
}

} // namespace NetworkCommissioning

namespace OnOff {

void DispatchServerCommand(app::Command * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv)
{
    {
        switch (aCommandId)
        {
        case ZCL_OFF_COMMAND_ID: {

            // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
            emberAfOnOffClusterOffCallback(apCommandObj);
            break;
        }
        case ZCL_ON_COMMAND_ID: {

            // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
            emberAfOnOffClusterOnCallback(apCommandObj);
            break;
        }
        case ZCL_TOGGLE_COMMAND_ID: {

            // TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
            emberAfOnOffClusterToggleCallback(apCommandObj);
            break;
        }
        default: {
            // Unrecognized command ID, error status will apply.
            apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kNotFound,
                                        Protocols::SecureChannel::Id, Protocols::SecureChannel::kProtocolCodeGeneralFailure);
            ChipLogError(Zcl, "Unknown command %" PRIx16 " for cluster %" PRIx16, aCommandId, ZCL_ON_OFF_CLUSTER_ID);
            break;
        }
        }
    }
}

} // namespace OnOff

} // namespace clusters

void DispatchSingleClusterCommand(chip::ClusterId aClusterId, chip::CommandId aCommandId, chip::EndpointId aEndPointId,
                                  chip::TLV::TLVReader & aReader, Command * apCommandObj)
{
    ChipLogDetail(Zcl, "Received Cluster Command: Cluster=%" PRIx16 " Command=%" PRIx8 " Endpoint=%" PRIx8, aClusterId, aCommandId,
                  aEndPointId);
    Compatibility::SetupEmberAfObjects(apCommandObj, aClusterId, aCommandId, aEndPointId);
    TLV::TLVType dataTlvType;
    SuccessOrExit(aReader.EnterContainer(dataTlvType));
    switch (aClusterId)
    {
    case ZCL_GENERAL_COMMISSIONING_CLUSTER_ID:
        clusters::GeneralCommissioning::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader);
        break;
    case ZCL_LEVEL_CONTROL_CLUSTER_ID:
        clusters::LevelControl::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader);
        break;
    case ZCL_NETWORK_COMMISSIONING_CLUSTER_ID:
        clusters::NetworkCommissioning::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader);
        break;
    case ZCL_ON_OFF_CLUSTER_ID:
        clusters::OnOff::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader);
        break;
    default:
        // Unrecognized cluster ID, error status will apply.
        apCommandObj->AddStatusCode(nullptr, Protocols::SecureChannel::GeneralStatusCode::kNotFound, Protocols::SecureChannel::Id,
                                    Protocols::SecureChannel::kProtocolCodeGeneralFailure);
        ChipLogError(Zcl, "Unknown cluster %" PRIx16, aClusterId);
        break;
    }
exit:
    Compatibility::ResetEmberAfObjects();
    aReader.ExitContainer(dataTlvType);
}

} // namespace app
} // namespace chip
